<?php

namespace common\services\myhtsq;

use common\entities\ContractEntity;
use common\error\ErrorCode;
use common\error\ErrorInfo;
use common\models\myhtsq\InvoiceModel;
use common\repositories\myhtsq\ContractEmailContactsRepository;
use common\repositories\myhtsq\ContractManageRepository;
use common\repositories\myhtsq\ContractPaymentRepository;
use common\repositories\myhtsq\ErpUserRepository;
use common\repositories\myhtsq\PaymentAchievementRepository;
use common\repositories\myhtsq\SignDelyRepository;
use common\services\BaseService;
use common\entities\ConfigEntity;
use common\models\myhtsq\DocumentModel;
use common\repositories\myhtsq\InvoiceRepository;
use common\repositories\myhtsq\InvoiceSummaryRepository;
use common\repositories\myhtsq\InvoiceReceivableRepository;
use common\repositories\myhtsq\InvoicePaymentRepository;
use common\repositories\myhtsq\DocumentRepository;
use common\repositories\myhtsq\ContractReceivableRepository;
use common\repositories\myhtsq\SpecialApprovalInvoiceRepository;
use common\repositories\myhtsq\InvoiceBusinessUnitRepository;
use common\services\common\EmailService;
use common\services\common\MyscrmContractSyncDeleteDataService;
use common\services\myhtsq\DocumentService;
use common\support\CsvExportHelper;
use common\support\ExcelManage;
use common\support\OSS;
use PHPExcel_Cell_DataType;
use PHPExcel_Style_Alignment;
use PHPExcel_Style_NumberFormat;
use yii\base\Exception;
use yii\helpers\ArrayHelper;
use common\support\StringHelper;

/**
 * Description of InvoiceService
 * 发票管理服务
 * @author chenxc
 */
class InvoiceService extends BaseService
{

    protected $_invoiceRepository;
    protected $_paymentRepository;
    protected $_invoicePaymentRepository;

    public function __construct(InvoiceRepository $invoiceRepository, ContractPaymentRepository $contractPaymentRepository, InvoicePaymentRepository $invoicePaymentRepository, $config = [])
    {
        $this->_invoiceRepository = $invoiceRepository;
        $this->_paymentRepository = $contractPaymentRepository;
        $this->_invoicePaymentRepository = $invoicePaymentRepository;
        parent::__construct($config);
    }

    /**
     * 发票管理模块：获取发票列表信息，支持分页
     * @param int $isMainInvoice 是否主发票
     * @param int $invoiceStatus 发票状态
     * @param int $invoiceBeginDate 开票开始日期
     * @param string $invoiceEndDate 开票结束日期
     * @param string $searchKey 查询关键字
     * @param int $pageIndex 页索引
     * @param int $pageSize 页大小
     * @return array PageResult
     */
    public function getInvoiceListByPage($isMainInvoice, $invoiceStatus, $invoiceBeginDate, $invoiceEndDate, $searchKey, $pageIndex, $pageSize,$invoice_mix_receipt=0)
    {
        return $this->_invoiceRepository->getInvoiceListByPage($isMainInvoice, $invoiceStatus, $invoiceBeginDate, $invoiceEndDate, $searchKey, $pageIndex, $pageSize,$invoice_mix_receipt);
    }

    /**
     * 保存发票
     * @param \common\models\myhtsq\InvoiceModel $invoiceModel
     * @return boolean|string   失败|发票Guid
     */
    public function saveInvoice($invoiceModel)
    {
        if ($invoiceModel->validate()) {

            if (($invoiceModel->is_red_invoice != 1 && $invoiceModel->is_reded_invoice != 1) && self::exitSameInvoiceNo($invoiceModel->invoice_no, $invoiceModel->invoice_id)) {
                return self::setAndReturn(ErrorCode::ERR_INVOICE_NO_EXIST_SAME);
            }

            // 开启事务
            $configDataBase = ContractEntity::getDb();
            $trans = $configDataBase->beginTransaction();

            try {

                //红冲发票与被红冲发票的receivables_amount、payment_amount都要置为0，对应应收款的已开票金额要更新
                if ($invoiceModel->is_red_invoice == 1) {
                    $invoiceModel->receivables_amount = 0;
                    $invoiceModel->payment_amount = 0;

                    $redInvoiceResult = $this->__redInvoice($invoiceModel->red_by_invoice_id);
                    if ($redInvoiceResult === false) {
                        $trans->rollBack();
                        return self::setAndReturn(__LINE__, '红冲发票失败');
                    }
                }

                if (isset($invoiceModel->invoice_id) && !empty($invoiceModel->invoice_id)) {
                    //修改
                    $result = InvoiceRepository::updateInvoice($invoiceModel);
                } else {
                    //新增
                    $result = InvoiceRepository::addInvoice($invoiceModel);
                }

                if ($result === false) {
                    // 回滚事务
                    $trans->rollBack();
                    return self::setAndReturn(InvoiceRepository::getErrCode());
                } else {
                    // 先删除原有的发票摘要
                    $res = InvoiceSummaryRepository::deleteInvoiceSummaryByInvoiceId($result);
                    if ($res !== true) {
                        // 回滚事务
                        $trans->rollBack();
                        return self::setAndReturn(InvoiceSummaryRepository::getErrCode());
                    }

                    // 再新增现有的发票摘要
                    $invoiceSummarys = $invoiceModel->invoiceSummarys;
                    if (count($invoiceSummarys) > 0) {
                        foreach ($invoiceSummarys as $k => $v) {
                            $v['invoice_id'] = $result;
                            $v['summary_id'] = null;
                            $res = InvoiceSummaryRepository::addInvoiceSummary($v);
                            if ($res === false) {
                                // 回滚事务
                                $trans->rollBack();
                                return self::setAndReturn(InvoiceSummaryRepository::getErrCode());
                            }
                        }
                    }

                    // 保存文档记录
                    $invoiceDocuments = $invoiceModel->invoiceDocuments;
                    if (isset($invoiceDocuments) && count($invoiceDocuments) > 0) {
                        foreach ($invoiceDocuments as $k => $v) {

                            if ($invoiceModel->is_red_invoice == 1) {
                                $v ['__type'] = 'add';
                            }elseif (!isset($v ['__type'])) {
                                $v ['__type'] = 'update';
                            }
                            
                            switch ($v ['__type']) {
                                case 'delete' :
                                    $res = DocumentRepository::delDocumentById($v['document_id']);
                                    if ($res === false) {
                                        // 回滚事务
                                        $trans->rollBack();
                                        return self::setAndReturn(DocumentRepository::getErrCode());
                                    }
                                    break;
                                case 'add' :
                                    $documentModel = new DocumentModel();
                                    $documentModel->setAttributes($v);
                                    $explode = explode('.', $v['document_name']);
                                    $extName = end($explode);
                                    $documentModel->document_ext_name = $extName;
                                    $documentModel->business_id = $result;
                                    if ($documentModel->validate()) {
                                        DocumentRepository::addDocument($documentModel);
                                        if ($res === false) {
                                            // 回滚事务
                                            $trans->rollBack();
                                            return self::setAndReturn(DocumentRepository::getErrCode());
                                        }
                                    }
                                    break;
                            }
                        }
                    }

                    // 提交事务
                    $trans->commit();
                    return $result;
                }
            } catch (Exception $e) {
                $trans->rollBack();
                return self::setAndReturn(__LINE__, (string)$e);
            }
        } else {
            return self::setAndReturn(ErrorCode::ERR_INVOICE_FORM_VERIFY_FAIL);
        }
    }

    /**
     * 红冲发票
     * @param $invoiceOldId
     * @return bool
     */
    private function __redInvoice($invoiceOldId)
    {
        //如有关联了回款、相关的回款业绩、交付业绩、都要取消关联或者删除。

        //更新被红冲发票的receivables_amount、payment_amount字段，重新刷新应收款的received_amount。
        $invoiceEntityOld = $this->getInvoiceEntity($invoiceOldId);
        $invoiceEntityOld->invoice_id = $invoiceOldId;
        $invoiceEntityOld->receivables_amount = 0;
        $invoiceEntityOld->payment_amount = 0;
        $invoiceEntityOld->is_reded_invoice = 1;
        $updateOldResult = $invoiceEntityOld->save();
        if ($updateOldResult === false) {
            return self::setAndReturn(InvoiceRepository::getErrCode());
        }

        //处理回款
        /** @var ContractPaymentService $contractPaymentService */
        $contractPaymentService = \Yii::createObject(ContractPaymentService::className());
        $invoicePaymentList = $contractPaymentService->getContractPaymentInfoByInvoiceId($invoiceOldId);

        if (!empty($invoicePaymentList)) {
            foreach ($invoicePaymentList as $item) {
                // 删除 回款与发票及应收款对应关系
                $deleteInvoicePaymentResult = InvoicePaymentRepository::deleteInvoicePaymentByInvoicePaymentId($item['invoice_payment_id']);
                if ($deleteInvoicePaymentResult === false) {
                    return self::setAndReturn(ErrorCode::ERR_CONTRACT_PAYMENT_DELETE_FAIL);
                }

                // 删除对应的回款业绩
                $deletePaymentAchievementResult = PaymentAchievementRepository::deletePaymentAchievementByPaymentId($item['payment_id']);
                if ($deletePaymentAchievementResult === false) {
                    return self::setAndReturn(ErrorCode::ERR_CONTRACT_PAYMENT_DELETE_FAIL);
                }

                // 删除交付业绩
                $deleteSignDelyResult = SignDelyRepository::deleteSignDelyByPaymentId($item['payment_id']);
                if ($deleteSignDelyResult === false) {
                    return self::setAndReturn(ErrorCode::ERR_CONTRACT_PAYMENT_DELETE_FAIL);
                }

                // 重新刷新应收款的received_amount
                $summaryContractReceivableResult = $contractPaymentService->summaryContractReceivableReceivedAmount($item['receivable_id']);
                if ($summaryContractReceivableResult === false) {
                    return self::setAndReturn(ErrorCode::ERR_CONTRACT_PAYMENT_DELETE_FAIL);
                }
            }
        }

        //处理应收款
        //重新刷新应收款的已开票金额
        $receivableIds = [];
        // 获取 发票与应收款对应关系记录
        $invoiceReceivables = InvoiceReceivableRepository::getInvoiceReceivablesByInvoiceId($invoiceOldId);
        if (isset($invoiceReceivables) && count($invoiceReceivables) > 0) {
            foreach ($invoiceReceivables as $k => $v) {
                if (isset($v['receivable_id']) && !empty($v['receivable_id']) && !in_array($v['receivable_id'], $receivableIds)) {
                    $receivableIds[] = $v['receivable_id'];
                }
            }
        }

        $deleteInvoiceReceivableResult = InvoiceReceivableRepository::deleteInvoiceReceivableByInvoiceId($invoiceOldId);
        if (!$deleteInvoiceReceivableResult) {
            return self::setAndReturn(ErrorCode::ERR_INVOICE_FORM_SAVE_FAIL);
        }

        foreach ($receivableIds as $k => $v) {
            // 根据应收款ID重新刷新应收款的billing_amount
            $res = ContractReceivableService::summaryReceivablesAmount($v);
            if (!$res) {
                return self::setAndReturn(ErrorCode::ERR_INVOICE_DELETE_FAIL);
            }
        }

        return true;
    }

    /**
     * 根据发票ID删除对应的发票信息
     * @param string $invoiceId 发票ID
     * @param boolean $fromContract 来自合同模块中的删除
     * @return boolean 返回true时表示删除成功，否则失败
     */
    public function deleteInvoice($invoiceId, $fromContract = false)
    {
        $invoiceEntity = InvoiceRepository::getInvoiceEntity($invoiceId);
        if (!isset($invoiceEntity)) {
            return self::setAndReturn(ErrorCode::ERR_INVOICE_NOT_EXISTS);
        }

        if (intval($invoiceEntity->is_reded_invoice) === 1) {
            return ErrorInfo::setAndReturn(__LINE__, '被红冲发票，不允许删除');
        }

        // 开启事务
        $configDataBase = ContractEntity::getDb();
        $trans = $configDataBase->beginTransaction();

        try {

            $deleteResult = $this->deleteInvoiceBiz($invoiceEntity, $fromContract);
            if($deleteResult === false){
                $trans->rollBack();
                return self::setAndReturn(__LINE__, self::getErrMsg());
            }

            // 删除红冲发票，需要把被红冲发票一并删除
            if (intval($invoiceEntity->is_red_invoice) === 1) {
                $invoiceOldEntity = InvoiceRepository::getInvoiceEntity($invoiceEntity->red_by_invoice_id);

                if (!empty($invoiceOldEntity)) {
                    $deleteOldResult = $this->deleteInvoiceBiz($invoiceOldEntity, $fromContract);
                    if($deleteOldResult === false){
                        $trans->rollBack();
                        return self::setAndReturn(__LINE__, self::getErrMsg());
                    }
                }
            }

            $trans->commit();
        }catch (\Exception $e){
            $trans->rollBack();
            return self::setAndReturn(__LINE__, self::getErrMsg());
        }

        return true;
    }

    /**
     * 删除发票时删除发票的业务数据
     * @param $invoiceEntity
     * @param bool $fromContract
     * @return bool
     */
    public function deleteInvoiceBiz($invoiceEntity, $fromContract = false)
    {
        if (!$fromContract) {
            if (isset($invoiceEntity['receivables_amount']) && floatval($invoiceEntity['receivables_amount']) > 0) {
                return ErrorInfo::setAndReturn(__LINE__, '发票已经关联了应收款，不允许删除');
            }
        }

        if (isset($invoiceEntity['payment_amount']) && floatval($invoiceEntity['payment_amount']) > 0) {
            return ErrorInfo::setAndReturn(__LINE__, '发票已经关联了回款，不允许删除');
        }

        $result = InvoiceRepository::deleteInvoice($invoiceEntity->invoice_id);
        if ($result !== true) {
            return self::setAndReturn(InvoiceRepository::getErrCode());
        }

        // 删除发票摘要
        $result = InvoiceSummaryRepository::deleteInvoiceSummaryByInvoiceId($invoiceEntity->invoice_id);
        if ($result !== true) {
            return self::setAndReturn(InvoiceSummaryRepository::getErrCode());
        }

        // 删除特批发票
        $specialApprovalInvoiceService = new SpecialApprovalInvoiceService(new SpecialApprovalInvoiceRepository());
        $result = $specialApprovalInvoiceService->delSpecialApprovalInvoiceByInvoiceNumber($invoiceEntity['invoice_no']);
        if ($result === FALSE) {
            return self::setAndReturn($specialApprovalInvoiceService::getErrCode());
        }

        if ($fromContract) {
            $receivableIds = [];
            // 获取 发票与应收款对应关系记录
            $invoiceReceivables = InvoiceReceivableRepository::getInvoiceReceivablesByInvoiceId($invoiceEntity->invoice_id);
            if (isset($invoiceReceivables) && count($invoiceReceivables) > 0) {
                foreach ($invoiceReceivables as $k => $v) {
                    if (isset($v['receivable_id']) && !empty($v['receivable_id']) && !in_array($v['receivable_id'], $receivableIds)) {
                        $receivableIds[] = $v['receivable_id'];
                    }
                }
            }

            $res = InvoiceReceivableRepository::deleteInvoiceReceivableByInvoiceId($invoiceEntity->invoice_id);
            if (!$res) {
                return self::setAndReturn(ErrorCode::ERR_INVOICE_DELETE_FAIL);
            }

            foreach ($receivableIds as $k => $v) {
                // 根据应收款ID重新刷新应收款的billing_amount
                $res = ContractReceivableService::summaryReceivablesAmount($v);
                if (!$res) {
                    return self::setAndReturn(ErrorCode::ERR_INVOICE_DELETE_FAIL);
                }
            }
        }

        return true;
    }

    /**
     * 根据发票ID设置当前发票成遗失状态
     * @param string $invoiceId 发票ID
     * @return boolean 返回true时表示设置成功，否则失败
     */
    public function doLose($invoiceId)
    {
        if (!InvoiceRepository::isExistInvoice($invoiceId)) {
            return self::setAndReturn(ErrorCode::ERR_INVOICE_NOT_EXISTS);
        }

        // 开启事务
        $configDataBase = ContractEntity::getDb();
        $trans = $configDataBase->beginTransaction();

        $result = InvoiceRepository::doLose($invoiceId);
        if ($result !== true) {
            $trans->rollBack();
            return self::setAndReturn(InvoiceRepository::getErrCode());
        }

        $receivableIds = [];
        $invoiceReceivables = InvoiceReceivableRepository::getInvoiceReceivablesByInvoiceId($invoiceId);
        if (isset($invoiceReceivables) && count($invoiceReceivables) > 0) {
            foreach ($invoiceReceivables as $k => $v) {
                $receivableIds[] = $v['receivable_id'];
                // 2、删除myscrm_invoice_payment对应的记录
                $result = InvoicePaymentRepository::deleteInvoicePaymentByInvoiceReceivableId($v['invoice_receivable_id']);
                if (!$result) {
                    $trans->rollBack();
                    return self::setAndReturn(ErrorCode::ERR_INVOICE_FORM_SAVE_FAIL);
                }
            }
        }

        // 3、删除myscrm_invoice_receivable对应的记录
        $result = InvoiceReceivableRepository::deleteInvoiceReceivableByInvoiceId($invoiceId);
        if (!$result) {
            $trans->rollBack();
            return self::setAndReturn(ErrorCode::ERR_INVOICE_FORM_SAVE_FAIL);
        }

        // 4、更新合同应收款中的billing_amount、received_amount
        foreach ($receivableIds as $k => $v) {
            $contractReceivableEntity = ContractReceivableRepository::getContractReceivableById($v);
            if (isset($contractReceivableEntity)) {
                $billingAmount = InvoiceReceivableRepository::getTotalBillingAmountByReceivableId($v);
                $receivedAount = InvoicePaymentRepository::getTotalPaymentAmountByReceivableId($v);

                $contractReceivableEntity->billing_amount = $billingAmount;
                $contractReceivableEntity->received_amount = $receivedAount;
                $result = $contractReceivableEntity->update();
                if ($result === false) {
                    $trans->rollBack();
                    return self::setAndReturn(ErrorCode::ERR_INVOICE_FORM_SAVE_FAIL);
                }
            }
        }

        $trans->commit();
        return true;
    }

    /**
     * 根据发票ID获取发票信息
     * @param string $invoiceId
     * @return array
     */
    public function getInvoiceInfo($invoiceId)
    {
        $invoice = InvoiceRepository::getInvoiceInfo($invoiceId);
        $summarys = InvoiceSummaryRepository::getInvoiceSummarysByInvoiceId($invoiceId);
        $invoiceDocuments = DocumentService::getDocumentListByBusinessId($invoiceId);

        $invoice['invoiceSummarys'] = $summarys;
        $invoice['invoiceDocuments'] = $invoiceDocuments;

        return $invoice;
    }

    /**
     * 根据合同ID获取对应的发票信息
     * @param string $contractId
     * @return array
     */
    public function getInvoiceListByContractId($contractId)
    {
        $invoices = InvoiceRepository::getInvoiceListByContractId($contractId);
        if (isset($invoices) && count($invoices) > 0) {
            foreach ($invoices as $k => $v) {
                $main_invoice_no = '';
                if ($v['is_child_invoice'] == 1 && !empty($v['main_invoice_id'])) {
                    $mainInvoice = InvoiceRepository::getInvoiceEntity($v['main_invoice_id']);
                    if (isset($mainInvoice)) {
                        $main_invoice_no = $mainInvoice['invoice_no'];
                    }
                }
                $invoices[$k]['main_invoice_no'] = $main_invoice_no;

                $summarys = InvoiceSummaryRepository::getInvoiceSummarysByInvoiceId($v['invoice_id']);
                $invoices[$k]['invoiceSummarys'] = $summarys;
                $invoiceDocuments = DocumentService::getDocumentListByBusinessId($v['invoice_id']);
                $invoices[$k]['invoiceDocuments'] = $invoiceDocuments;
            }
        }

        return $invoices;
    }

    /**
     * 特批界面获取发票select2控件下拉选项
     * @param string $keyword 搜索关键字
     * @param string $limit 只显示几条记录
     */
    public static function getInvoiceListForSepcialInvoiceSelect2($keyword, $limit)
    {
        return InvoiceRepository::getInvoiceListForSepcialInvoiceSelect2($keyword, $limit);
    }

    /**
     * 根据发票ID重新刷新发票的receivables_amount
     * @param string $invoiceId
     * @return boolean true刷新成功/false刷新失败
     */
    public static function summaryReceivablesAmount($invoiceId)
    {
        $totalAmount = 0;
        $invoice = InvoiceRepository::getInvoiceEntity($invoiceId);
        if (!isset($invoice)) {
            return self::setAndReturn(ErrorCode::ERR_INVOICE_NOT_EXISTS);
        }

        $invoiceReceivables = InvoiceReceivableRepository::getInvoiceReceivablesByInvoiceId($invoiceId);
        if (isset($invoiceReceivables) && count($invoiceReceivables) > 0) {
            foreach ($invoiceReceivables as $k => $v) {
                $totalAmount += floatval($v['cur_billing_amount']);
            }
        }

        $invoice->receivables_amount = $totalAmount;
        $result = $invoice->update();

        if ($result === false) {
            return $result;
        }

        return true;
    }

    /**
     * 重新刷新发票的回款金额
     * @param string $invoiceId 发票ID
     * @return boolean true刷新成功/false刷新失败
     */
    public static function summaryInvoicePaymentAmount($invoiceId)
    {
        $invoice = InvoiceRepository::getInvoiceEntity($invoiceId);
        if (!isset($invoice)) {
            return false;
        }

        $totalPaymentAmount = InvoicePaymentRepository::getTotalPaymentAmountByInvoiceId($invoiceId);
        $invoice->payment_amount = $totalPaymentAmount;
        $affectedRowNum = $invoice->update();
        if ($affectedRowNum === false) {
            return false;
        }

        return true;
    }

    /**
     * 获取可以作为父级发票的发票信息
     * @param string $keyword
     * @return array
     */
    public function getParentInvoiceInfo($keyword)
    {
        return InvoiceRepository::getParentInvoiceInfo($keyword);
    }

    /**
     * 根据发票id获取发票的entity对象
     * @param string $invoiceId 发票ID
     * @return \common\entities\myhtsq\InvoiceEntity
     */
    public static function getInvoiceEntity($invoiceId)
    {
        return InvoiceRepository::getInvoiceEntity($invoiceId);
    }

    /**
     * 获取所有可以被引用的发票信息
     * @param string $contractId
     * @return array
     */
    public function getCanUseInvoiceInfo($contractId = null, $keyword = null)
    {
        $result = InvoiceRepository::getCanUseInvoiceInfo($contractId, $keyword);
        return $result;
    }

    /**
     * 检查是否存在相同发票代码的发票
     * @param string $invoiceCode 发票代码
     * @param string $invoiceId 发票id
     * @return boolean true存在/false不存在
     */
    public static function exitSameInvoiceCode($invoiceCode, $invoiceId = null)
    {
        return InvoiceRepository::exitSameInvoiceCode($invoiceCode, $invoiceId);
    }

    /**
     * 检查是否存在相同发票编号的发票
     * @param string $invoiceNo 发票编号
     * @param string $invoiceId 发票id
     * @return boolean true存在/false不存在
     */
    public static function exitSameInvoiceNo($invoiceNo, $invoiceId = null)
    {
        return InvoiceRepository::exitSameInvoiceNo($invoiceNo, $invoiceId);
    }

    /**
     * 判断主发票的开票金额是否不小于所有子发票的开票金额
     * @param string $mainInvoiceId
     * @return boolean true校验通过，false校验不通过
     */
    public static function checkMainInvoiceAmountMorethanChildAmount($mainInvoiceId)
    {
        $parentInvoice = InvoiceRepository::getInvoiceEntity($mainInvoiceId);
        if (isset($parentInvoice)) {
            $parentInvoiceAmount = $childInvoiceAmount = 0;
            if (isset($parentInvoice['invoice_amount']) && !empty($parentInvoice['invoice_amount'])) {
                $parentInvoiceAmount = floatval($parentInvoice['invoice_amount']);
            }

            $childInvoices = InvoiceRepository::getChildInvoiceInfo($mainInvoiceId);
            if (isset($childInvoices) && count($childInvoices) > 0) {
                foreach ($childInvoices as $k => $v) {
                    if (isset($v['invoice_amount']) && !empty($v['invoice_amount'])) {
                        $childInvoiceAmount += floatval($v['invoice_amount']);
                    }
                }
            }

            return $parentInvoiceAmount >= $childInvoiceAmount;
        }

        return true;
    }

    /**
     * 获取开票单位
     * @param string $keyword 搜索关键字
     * @return array
     */
    public function getInvoiceBusinessUnit($keyword = '')
    {
        return InvoiceBusinessUnitRepository::getInvoiceBusinessUnit($keyword);
    }

    /**
     * 获取开票单位
     * @param string $erpGUID
     * @return array|null|\yii\db\ActiveRecord
     */
    public function getInvoiceBusinessUnitByErpGuid($erpGUID)
    {
        return InvoiceBusinessUnitRepository::getInvoiceBusinessUnitByErpGuid($erpGUID);
    }

    /**
     * 过期未全部回款的发票发送提醒
     */
    public function invoiceExpiredRemind()
    {
        $expiredDate = date_add(date_create_from_format('Y-m-d H:i:s', ContractEntity::getDbNowDate()), \DateInterval::createFromDateString('-7 Day'));
        $expiredDate = date_format($expiredDate, 'Y-m-d');
        //获取开票七天仍未回完款发票
        $expiredInvoices = InvoiceRepository::getExpiredInvoices($expiredDate);
        foreach ($expiredInvoices as $key => $item) {
            //获取合同信息
            $contractInfo = ContractManageRepository::getContractManageModelByContractId($item['contract_id']);
            //获取发票对应的未回完款的应收
            $noReceived = ContractReceivableRepository::getNoReceivedByInvoice($item['invoice_id']);
            foreach ($noReceived as $key2 => $item2) {
                $emailParams = [
                    'contractId' => $contractInfo->contract_code,
                    'custName' => $contractInfo->customer_name,
                    'invoiceAmount' => $item2['billing_amount'],
                    'remainAmount' => ($item2['billing_amount'] - $item2['received_amount']) . '(发票'
                        . $item['invoice_amount'] . ',绑定应收' . $item2['billing_amount'] . ',绑定回款' . $item2['received_amount'] . ')',
                    'invoiceDate' => $item['invoice_date']
                ];
                $this->sendEmail($item2['payee_id'], '【合同管理】已开票未全部回款', 'invoiceExpired', $emailParams, []);
            }

        }
    }

    private function sendEmail($userId, $subject, $template, $params, $cc)
    {
        $user = ErpUserRepository::getUserById($userId);
        if (empty($user)) {
            return;
        }
        //获取抄送人
        $copyToEMail = ContractEmailContactsRepository::getCCContactsByBu($user['BUGUID'], $user['UserCode']);

        $params['ScrmUrl'] = \Yii::$app->params['ScrmUrl'];
        $params['userName'] = $user['UserName'];

        if (is_array($cc)) {
            $copyToEMail = array_merge($copyToEMail, $cc);
        }
        $params['ScrmUrl'] = \Yii::$app->params['ScrmUrl'];
        return EmailService::sendEMail([$user['Email'] => $user['UserName']], $subject, 'contract/' . $template, $params, $copyToEMail);
    }

    /**
     *
     * 发票管理模块：导出发票/收据列表信息
     * @param int $isMainInvoice 是否主发票
     * @param int $invoiceStatus 发票状态
     * @param int $invoiceBeginDate 开票开始日期
     * @param string $invoiceEndDate 开票结束日期
     * @param string $searchKey 查询关键字
     * @param $isReceipt
     * @return array PageResult
     * @throws \PHPExcel_Exception
     */
    public function exportInvoiceListExcel($isMainInvoice, $invoiceStatus, $invoiceBeginDate, $invoiceEndDate, $searchKey, $isReceipt)
    {
        $data = $this->_invoiceRepository->getInvoiceListForExport($isMainInvoice, $invoiceStatus, $invoiceBeginDate, $invoiceEndDate, $searchKey, $isReceipt);

        $typeCn = '发票';
        if ($isReceipt == 1) {
            $typeCn = '收据';
        }
        $objPHPExcel = new \PHPExcel();
        //设置当前的sheet
        $objPHPExcel->setActiveSheetIndex(0);
        //设置sheet的name
        $objPHPExcel->getActiveSheet()->setTitle('Simple');
        //设置对齐方式
        $objPHPExcel->getActiveSheet()->getStyle('A:O')->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);

        //设置单元格的值
        $objPHPExcel->getActiveSheet()->setCellValue('A1', '开票单位');
        $objPHPExcel->getActiveSheet()->setCellValue('B1', '开票单位');
        $objPHPExcel->getActiveSheet()->setCellValue('C1', $typeCn . '类别');
        $objPHPExcel->getActiveSheet()->setCellValue('D1', $typeCn . '代码');
        $objPHPExcel->getActiveSheet()->setCellValue('E1', $typeCn . '号码');
        $objPHPExcel->getActiveSheet()->setCellValue('F1', '开票日期');
        $objPHPExcel->getActiveSheet()->setCellValue('G1', '开通金额');
        $objPHPExcel->getActiveSheet()->setCellValue('H1', '摘要');
        $objPHPExcel->getActiveSheet()->setCellValue('I1', '客户名称');
        $objPHPExcel->getActiveSheet()->setCellValue('J1', '签约客户全称');
        $objPHPExcel->getActiveSheet()->setCellValue('K1', '合同编号');
        $objPHPExcel->getActiveSheet()->setCellValue('L1', $typeCn . '类型');
        $objPHPExcel->getActiveSheet()->setCellValue('M1', '合同所属区域');
        $objPHPExcel->getActiveSheet()->setCellValue('N1', '申请人');
        $objPHPExcel->getActiveSheet()->setCellValue('O1', '备注');

        if (!empty($data)) {
            $j = 2;
            foreach ($data as $key => $val) {
                $i = 'A';
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['invoiceCompanyName']); // 开票单位
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['invoiceCompanyName']); // 开票单位
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $this->transformInvoiceCategoryToChinese($val['invoice_category'])); //发票类别
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['invoice_code']); //发票代码
                $i++;
                $objPHPExcel->getActiveSheet()->getStyle($i . $j)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_TEXT);
                $objPHPExcel->getActiveSheet()->setCellValueExplicit($i . $j, $val['invoice_no'], PHPExcel_Cell_DataType::TYPE_STRING); //发票号码
                $i++;
                $objPHPExcel->getActiveSheet()->getStyle($i . $j)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2);
                $objPHPExcel->getActiveSheet()->setCellValueExplicit($i . $j,(strtotime(date('Y-m-d',strtotime($val['invoice_date'])))+8*60*60)/(24*60*60)+25569, PHPExcel_Cell_DataType::TYPE_NUMERIC); //开票日期
                //$objPHPExcel->getActiveSheet()->setCellValue($i . $j, StringHelper::formatDate($val['invoice_date'], 'Y-m-d')); //开票日期
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['invoice_amount']); //开通金额
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['summary_type']); //摘要
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['customer_name']); //客户名称
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['customer_full_name']); //签约客户全称
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['contractCode']); //合同编号
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $this->transformInvoceTypeToChinese($val['invoice_type'])); //发票类型
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['area_name']); //合同所属区域
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['UserName']); //申请人
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['remark']); //备注
                $j++;
            }
        }

        $objPHPExcel->getActiveSheet()->getColumnDimension('A')->setVisible(false); //把合同guid 设置为隐藏列
        $objWriter = new \PHPExcel_Writer_Excel5($objPHPExcel);
        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control:must-revalidate, post-check=0, pre-check=0");
        header("Content-Type:application/force-download");
        header("Content-Type:application/vnd.ms-execl");
        header("Content-Type:application/octet-stream");
        header("Content-Type:application/download");;
        header('Content-Disposition:attachment;filename=' . $typeCn . '清单' . date("YmdHis") . '.xls');
        header("Content-Transfer-Encoding:binary");
        $objWriter->save('php://output');
        exit;
    }


    /**
     * 转换发票类别
     * @param $invoceCategory
     * @return string
     */
    public function transformInvoiceCategoryToChinese($invoceCategory)
    {

        switch ($invoceCategory){
            case 0:
                $invoceCategoryType = '销售票';
                break;
            case 1:
                $invoceCategoryType = '服务票';
                break;
            //todo
            default:
                $invoceCategoryType = '';
        }
        return $invoceCategoryType;

    }

    /**
     * 转换发票类型
     * @param $invoceType
     * @return string
     */
    public function transformInvoceTypeToChinese($invoceType)
    {
        switch ($invoceType){
            case 0:
                $invoceTypeForChinese = '增值税普通发票';
                break;
            case 1:
                $invoceTypeForChinese = '增值税专用发票';
                break;
            //todo
            default:
                $invoceTypeForChinese = '';
        }
        return $invoceTypeForChinese;
    }

    /**
     * 导出未关联发票的回款明细
     * @return array PageResult
     * @throws \PHPExcel_Exception
     */
    public function exportUnInvoicePayment()
    {
        $hasInvoicePayments = $this->_invoicePaymentRepository->getAllList();
        $hasInvoicePaymentIds = ArrayHelper::getColumn($hasInvoicePayments, 'payment_id');

        $data = $this->_paymentRepository->getUnInvoicePayment($hasInvoicePaymentIds);

        $objPHPExcel = new \PHPExcel();
        //设置当前的sheet
        $objPHPExcel->setActiveSheetIndex(0);
        //设置sheet的name
        $objPHPExcel->getActiveSheet()->setTitle('Simple');

        //设置单元格的值
        $objPHPExcel->getActiveSheet()->setCellValue('A1', '合同编号');
        $objPHPExcel->getActiveSheet()->setCellValue('B1', '财务编号');
        $objPHPExcel->getActiveSheet()->setCellValue('C1', '实收总额');
        $objPHPExcel->getActiveSheet()->setCellValue('D1', '实收时间');
        $objPHPExcel->getActiveSheet()->setCellValue('E1', '实收款编号');
        $objPHPExcel->getActiveSheet()->setCellValue('F1', '收款账号');
        $objPHPExcel->getActiveSheet()->setCellValue('G1', '付款客户名称');

        if (!empty($data)) {
            $j = 2;
            foreach ($data as $key => $val) {
                $i = 'A';
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['contract_code']); // 合同编号
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['finance_code']); // 财务编号
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['payment_amount']); // 实收总额
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, date('Y-m-d', strtotime($val['payment_date']))); //实收时间
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['payment_code']); //实收款编号
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['receivables_account_name']); //收款账号
                $i++;
                $objPHPExcel->getActiveSheet()->setCellValue($i . $j, $val['payment_account_name']); //付款客户名称
                $i++;

                $j++;
            }
        }
        $objWriter = new \PHPExcel_Writer_Excel5($objPHPExcel);
        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control:must-revalidate, post-check=0, pre-check=0");
        header("Content-Type:application/force-download");
        header("Content-Type:application/vnd.ms-execl");
        header("Content-Type:application/octet-stream");
        header("Content-Type:application/download");;
        header('Content-Disposition:attachment;filename="未关联发票的回款明细-' . date("YmdHis") . '.xls"');
        header("Content-Transfer-Encoding:binary");
        $objWriter->save('php://output');
        exit;
    }

    /**
     * 根据发票id获取发票信息
     * @param string $invoiceId
     * @return mixed
     */
    public function getInvoiceInfoById($invoiceId)
    {
        return InvoiceRepository::getInvoiceInfoById($invoiceId);
    }

    /**
     * 根据contractId检查发票是否存在
     * @param $contractId
     * @return bool
     */
    public static function checkInvoiceExists($contractId)
    {
        return InvoiceRepository::checkInvoiceExists($contractId);
    }

    /**
     * 通过Excel导入发票
     * @param string $filePath
     * @return array|bool
     */
    public function importInvoiceByExcel($filePath) {
        ob_end_clean();
        try {
            $data = ExcelManage::importDataByFilePath($filePath, 2);
        }catch (\PHPExcel_Exception $exception) {
            return self::setAndReturn(-1, 'PHPExcel插件异常：'.$exception->getMessage().'，请重试');
        }
        if (!is_array($data)) {
            return self::setAndReturn(-1, 'Excel读取失败，请重试');
        }

        $errors = array();              //错误信息
        $errorCount = 0;                //错误信息数
        $alreadyImportData = array();   //可导入的数据
        $exportData = $data;            //待导出的错误数据

        //文件中发票号码查重
        $invoiceNum = array_filter(array_column($data, 3),function($val){
            if($val===''||$val===null){
                return false;
            }else{
                return true;
            }
        });
        $numUnique = array_unique($invoiceNum);
        if (count($invoiceNum) != count($numUnique)) {
            foreach (array_diff_key($invoiceNum,$numUnique) as $key => $v) {
                $errors[$key] .= '该发票号码在Excel中有重复。';
                $errorCount++;
            }
        }

        $i = 0;
        // 格式判断 并去除空行
        foreach ($data as $key => $row) {
            $i++;
            if ($i == 1) {
                //字段名判断
                if (array_splice($row, 0, 12) != ["发票类别", "发票代码", "发票类型", "发票号码", "申请人", "客户名称", "开票单位", "开票金额", "开票日期", "摘要类型", "摘要金额", "备注"]) {
                    return self::setAndReturn(-1, '选择模板有误，请重新选择导入内容');
                }
                //去除标题
                unset($data[$key]);
                continue;
            }
            //去除空行
            if (array_slice($row, 0, 12) == ["", "", "", "", "", "", "", "", "", "", "", ""]) {
                unset($data[$key]);
                continue;
            }

            // 不能为空 除备注之外
            for ($c = 0;$c < 11; $c++) {
                if (empty($row[$c])) {
                    $errors[$i] .=  '必填项为空。';
                    $errorCount++;
                    break;
                }
            }

            /*
             * 格式转换
             */
            // 发票类别转换
            $row[0] = $this->transformInvoiceCategoryStrToNum($row[0]);
            if ($row[0] === false) {
                $errors[$i] .= '发票类别不存在。';
                $errorCount++;
            }

            // 发票类型转换
            $row[2] = $this->transformInvoiceTypeStrToNum($row[2]);
            if ($row[2] === false) {
                $errors[$i] .= '发票类型不存在。';
                $errorCount++;
            }

            // 通过名字查询申请人ID
            if (!empty($row[4])) {
                $users = ErpUserRepository::getErpUserByKeyword($row[4]);
                if (count($users) > 1){
                    $errors[$i] .= '申请人有重名，请手工录入。';
                    $errorCount++;
                }elseif(!$users) {
                    $errors[$i] .= '申请人不存在。';
                    $errorCount++;
                }else {
                    $row[4] = $users[0]['UserGUID'];
                }
            }

            // 开票单位名称转id
            $invoiceBusinessUnit = $this->getInvoiceBusinessUnit($row[6]);
            if ($invoiceBusinessUnit) {
                $row[6] = $invoiceBusinessUnit[0]->BUGUID;
            }else {
                $errors[$i] .= '开票单位不匹配。';
                $errorCount++;
            }

            // 开票日期转换
            if (is_numeric($row[8]) && strlen(explode('.',$row[8])[0]) <= 5) {
                $row[8] = date('Y-m-d', \PHPExcel_Shared_Date::ExcelToPHP($row[8]));
            }else {
                $errors[$i] .= '开票日期不是日期格式。';
                $errorCount++;
            }

            //发票号码查重
            if (InvoiceRepository::exitSameInvoiceNo($row[3])) {
                $errors[$i] .= '该发票号码在数据库中有重复。';
                $errorCount++;
            }

            //摘要类型判断
            if (!in_array($row[9],['软件技术服务费','软件服务费','服务费','明源云客电子商务平台－移动销售系统V1.0','明源云客来访登记系统V1.0','广告费','广告发布费'])) {
                $errors[$i] .= '摘要类型不匹配。';
                $errorCount++;
            }

            //发票金额 与 摘要金额和 必须相等
            if ($row[10] != $row[7]) {
                $errors[$i] .= '发票金额与摘要金额不相等。';
                $errorCount++;
            }

            /*数据整合*/
            $invoice['invoice_category'] = $row[0];
            $invoice['invoice_code']   = $row[1];
            $invoice['invoice_type']       = $row[2];
            $invoice['invoice_no']         = $row[3];
            $invoice['proposer_id']       = $row[4];
            $invoice['customer_name']     = $row[5];
            $invoice['invoice_company_id']      = $row[6];
            $invoice['invoice_amount']       = $row[7];
            $invoice['invoice_date']        = $row[8];
            $invoice['remark']             = $row[11];
            $invoice['invoiceSummarys']    = [
                ['summary_type'   => $row[9],
                    'summary_amount' => $row[10],]
            ];

            $invoiceModel = new InvoiceModel(['scenario' => 'saveinvoice']);
            $invoiceModel->setAttributes($invoice);
            $invoiceModel->is_import = 1;

            if (empty($errors[$i])) {
                $alreadyImportData[$key] = $invoiceModel;
            }
        }

        if (empty($data)) {
            return self::setAndReturn(-1, 'Excel中没有发票数据');
        }

        foreach ($alreadyImportData as $invoice) {
            $this->saveInvoice($invoice);
        }

        //如果有错误 导出错误清单
        if ($errorCount > 0) {
            $exportData[2][12] = '错误信息';
            foreach ($exportData as $rowIndex => $rows) {
                if (!empty($errors[$rowIndex])) {
                    $exportData[$rowIndex+1][12] = $errors[$rowIndex];
                }
            }

            $path =  $this->exportExcelByDataAndErrors($exportData, ['I'], '发票导入失败清单');
            self::setAndReturn(-1,'导入有错误，详情请下载发票导入失败清单');
            return $path;
        }else {
            return self::setAndReturn(0,'导入成功');
        }

    }

    /**
     * 发票类别转换
     * @param $invoiceCategoryStr
     * @return bool|int 1: 服务票 0: 销售票 false: 没有该发票类别
     */
    public function transformInvoiceCategoryStrToNum($invoiceCategoryStr) {

        switch ($invoiceCategoryStr) {
            case '服务票':
                $invoiceCategoryNum = 1;
                break;
            case '销售票':
                $invoiceCategoryNum = 0;
                break;
            default:
                $invoiceCategoryNum = false;
        }
        return $invoiceCategoryNum;
    }

    /**
     * 发票类型转换
     * @param $invoiceTypeStr
     * @return bool|int 1: 增值税专用发票 0: 增值税普通发票 false: 没有该发票类型
     */
    public function transformInvoiceTypeStrToNum($invoiceTypeStr) {
        switch ($invoiceTypeStr) {
            case '增值税专用发票':
                $invoiceTypeNum = 1;
                break;
            case '增值税普通发票':
                $invoiceTypeNum = 0;
                break;
            default:
                $invoiceTypeNum = false;
        }
        return $invoiceTypeNum;
    }

    /**
     * 导出 导入发票的失败清单 zip方式保存
     * @param array $data         导入发票时的原始数据
     * @param array $dateIndex    选择需改成日期格式的所在列
     * @param string $fileName    导出文件名称
     * @return mixed
     */
    public function exportExcelByDataAndErrors($data, $dateIndex = array(), $fileName = 'exportExcel') {
        $objPHPExcel = new \PHPExcel();
        $objPHPExcel->setActiveSheetIndex(0);
        $objPHPExcel->getActiveSheet()->setTitle('Simple');

        /**
         * $rowIndex  Excel行编号
         * $rows      行数据
         * $i         列编号
         * $cellValue 单元格数据
         */
        foreach ($data as $rowIndex => $rows) {
            $i = 'A';
            foreach ($rows as $cellValue) {
                if (in_array($i, $dateIndex) && $rowIndex != 2) {
                    $objPHPExcel->getActiveSheet()->getStyle($i.$rowIndex)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2);
                }
                $objPHPExcel->getActiveSheet()->setCellValue($i.$rowIndex,$cellValue);
                $i++;
            }
        }


        $path = \Yii::getAlias("@mybackend/web/xls/");
        $fileName = $fileName.date('YmdHis'). \Yii::$app->user->identity->userguid . '.xls';
        // 文件名称
        if (!is_dir($path)) {
            mkdir($path, 0755);
        }

        $filePath = $path . $fileName;
        $objWriter = new \PHPExcel_Writer_Excel5($objPHPExcel);
        ob_end_clean();
        $objWriter->save($filePath);

        $zipName = 'qingdan'.date('YmdHis'). \Yii::$app->user->identity->userguid .'.zip';
        $zipPath = $path . $zipName;
        $zip = new \ZipArchive();
        $zip->open($zipPath, \ZipArchive::CREATE);
        $zip->addFile($filePath, basename($filePath));
        $zip->close();
        $key = $zipName;

        OSS::upload($key, $zipPath);
        $ossUrl = OSS::getUrl($key);
        return $ossUrl;
    }
}
